<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript" src="http://mkjs.net/git/encryptjs/encrypt.js"></script>
</head>
<body>

<script type="text/javascript">

var url = "http://localhost:55322/default.aspx";

function XOAuthRequest(url, data, fn){
	var xhr = new XMLHttpRequest();
	xhr.open('POST', url, true);
	xhr.addEventListener('load', function load(){
		this.removeEventListener('load', load);
		var result = (xhr.response || xhr.responseText) + '';
		result = decodeURIComponent(result);
		typeof(fn) == 'function' && fn(result);
		xhr = null;
	});
	// var form = null;
	// if(data){
	// 	form = new FormData();
	// 	for(var p in data){
	// 		form.append(p, data[p]);
	// 	}
	// }
	xhr.send(data);
};

function Base64ToArrayBuffer(base64){
	var bin = atob(base64);
	var arr = new Uint8Array(bin.length);
	arr.forEach(function(v, i, a){
		a[i] = bin.charCodeAt(i);
	});
	return arr.buffer;
}
function ArrayBufferToBase64(arrayBuffer){
	var byteArray = new Uint8Array(arrayBuffer);
	var byteStr = '';
	byteArray.forEach(function(v){
		byteStr += String.fromCharCode(v);
	});
	return btoa(byteStr);
}

var ASCII = new TextEncoder('ASCII');
var UTF8 = new TextEncoder('UTF-8');
function BuildData(X, data){
	X = X || '';
	var head = [X.length];
	ASCII.encode(X).forEach(function(v){
		head.push(v);
	});
	if(data && typeof(data) == 'string'){
		data = UTF8.encode(data);
	} else if(data instanceof ArrayBuffer){
		data = new Uint8Array(data);
	}
	if(data && data.forEach){
		data.forEach(function(v){
			head.push(v);
		});
	}
	data = null;
	return head;
}

function Base64Array(s){
	var a = [0];
	UTF8.encode(btoa(encodeURIComponent(s || ''))).forEach(function(v){ a.push(v); });
	return a;
}


function XOAuthClient(url){
	this.URL = url;
	this.ServerPublicKey = null;
};
XOAuthClient.prototype = {
	Request: function(data, fn){
		XOAuthRequest(this.URL, data, fn);
		return this;
	},
	x: function(){

		var args = Array.prototype.slice.call(arguments, 0);
		var x, data, enc = false, fn = args.pop();

		if(args.length >= 1){
			x = args.shift() || '';
			data = args.shift() || null;
			enc = !!args.shift();
		} else {
			x = data = null;
			enc = base64 = false;
		}
		var arr = BuildData(x, data);

		if(enc){
			this.encrypt(arr, function(en){
				var a = [0];
				new Uint8Array(en).forEach(function(v){
					a.push(v);
				});
				var blob = new Blob([new Uint8Array(a)]);
				return this.Request(blob, fn);
			});
		} else {
			var blob = new Blob([new Uint8Array(arr)]);
			return this.Request(blob, fn);
		}
	},
	encrypt: function(arr, fn){

		if(typeof(fn) != 'function') return;

		if(typeof(arr) == 'string'){
			arr = UTF8.encode(arr)
		}

		if(!arr.buffer){
			arr = new Uint8Array(arr);
		}

		fn = fn.bind(this);

		crypto.subtle
		.encrypt({ name: "RSA-OAEP" }, this.ServerPublicKey, arr.buffer)
		.then(function(encrypted){
			fn(encrypted)
		});

		return this;
	},
	ready: function(fn){

		if(typeof(fn) != 'function') return;

		var _ = this;
		fn = fn.bind(_);
		return this.x('KEY', function(key){
			var publicKey = Base64ToArrayBuffer(key);
			crypto.subtle
			.importKey('spki', publicKey, { name: "RSA-OAEP", hash: { name: "SHA-1" }}, false, ["encrypt"])
			.then(function(pubKey){
				_.ServerPublicKey = pubKey;

				crypto.subtle
				.generateKey({
					name: "RSA-OAEP",
					hash: { name: "SHA-1" },
					modulusLength: 2048,
					publicExponent: new Uint8Array([0x01, 0x00, 0x01])
				}, false, ["encrypt", "decrypt"])
				.then(function(keyPair){
					// _.ClientKeyPair = keyPair;
					_.ClientPrivateKey = keyPair.privateKey;
					crypto.subtle
					.exportKey('spki', keyPair.publicKey)
					.then(function(pubKey){
						_.ClientPublicKey = ArrayBufferToBase64(pubKey);

						var clientKey = new Uint8Array(pubKey);
						_.x('CLIENT-KEY', clientKey, function(resp){
							_.SessionId = resp;
							fn();
						})
					})
				})
			})
		});
	},
	test: function(msg, fn, base64){

		if(typeof(fn) != 'function') return;
		fn = fn.bind(this);

		var t = msg;
		if(base64){
			t = Base64Array(t);
		}

		this.x('TEST', t, function(resp){
			fn(resp, msg);
		});
		return this;
	},
	login: function(id, pwd, fn){

		if(typeof(fn) != 'function') return;
		fn = fn.bind(this);

		var ser = [id, encrypt.sha1(pwd), Date.now()].join('\n');
		var b64 = btoa(ser);
		console.log(b64)
		this.x('LOGIN', b64, true, function(resp){
			fn(resp);
		})
	}
};

var client = new XOAuthClient(url);
client.ready(function(){
	// console.log(this)
	this.test('中文和zhongwen8490*)(*)EWS_)R)', function(b, a){
		console.log(b === a)
	}, true);

	// this.login('mk', 'abc', function(resp){
	// 	console.log(resp)
	// })
});





</script>

</body>
</html>